/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __THREAD_H__
#define __THREAD_H__

#include "BaseType.h"
#include "ThreadUtil.h"
#include "Singleton.h"
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <vector>

namespace libemb{

/* 请注意:线程入口函数必须是void(void*arg),否则在函数中可能无法使用成员变量!!! */
using ThreadEntry = std::function<void(void*)>;
/**
 *  \file   Thread.h   
 *  \class  ThreadAttr
 *  \brief  线程属性类	
 */
class ThreadAttr{
public:
	enum SCHED_POLICY_E
	{
		SCHED_POLICY_OTHER = SCHED_OTHER, /* 0:普通调度策略,优先级只能设置为0 */
		SCHED_POLICY_FIFO = SCHED_FIFO,   /* 1:不同优先级抢占,同等优先级先进先出,优先级可以设置为1(低)~99(高) */
		SCHED_POLICY_RR = SCHED_RR, 	  /* 2:不同优先级抢占,同等优先级均分时间片,优先级可以设置为1(低)~99(高) */
	};

public:
	ThreadAttr(){};
	virtual ~ThreadAttr(){};
	int policy();		/* 可取值:SCHED_POLICY_FIFO(优先级1~99),SCHED_POLICY_RR(优先级1~99),SCHED_POLICY_OTHER(优先级固定为0) */
	int priority();	/* 可取值:1~99,数字越大，优先级越高 */
	int inherit();	    /* PTHREAD_INHERIT_SCHED(继承自父线程,忽略当前设置的属性),PTHREAD_EXPLICIT_SCHED(采用当前设置的线程属性) */
	int stackSize();/* 最小值为PTHREAD_STACK_MIN(16384) */
private:
	friend class Thread;
	int m_policy{SCHED_POLICY_OTHER};
	int m_priority{0};
	int m_inherit{PTHREAD_INHERIT_SCHED};
	int m_stackSize{PTHREAD_STACK_MIN};
	
};

/**
 *  \file   Thread.h   
 *  \class  Threading
 *  \brief  线程化类,用以线程化类成员函数
 */
class Threading{
public:
	Threading(){};
	virtual ~Threading(){};
	int threading(ThreadEntry entry,void* args);
private:
	static void* startRoutine(void *arg);
};


/**
 *  \file   Thread.h   
 *  \class  Runnable
 *  \brief  线程体,子类必须重写run方法.	
 */
class Runnable{
public:
	Runnable(){};
	virtual ~Runnable(){};
	virtual void run()=0;
	bool isRunning();
protected:
	void quit();
    bool checkCancel();
private:
    friend class ThreadPool;
	friend class Thread;
    bool m_runFlag{false};
};


/**
 *  \file   Thread.h   
 *  \class  Thread
 *  \brief  线程类	
 */
class Thread{
public:
	enum THREAD_STATE
	{
		STATE_EXIT=0,
	    STATE_START,
	    STATE_RUNNING,
	};
public:
	Thread();
	virtual ~Thread();
	static bool initWithPreemptRT(int policy, int priority);	/* 初始化为实时抢占系统 */
	static void usleep(int us);
	static void msleep(int ms);
	void setAttribute(int policy, int priority, bool inherit=false,int stackSize=0);
	bool start(const Runnable& runnable);
    bool stop(int usTimeout);
    bool forceQuit();
	bool isRunning();
private:
	bool pthreadAttrSet(pthread_attr_t& pAttr);
    void threadMain();
    static void* startRoutine(void *arg);
private:
	Runnable* m_pRunnable{NULL};
	int m_threadStatus{STATE_EXIT};
	pthread_t m_threadID{0};
	pthread_attr_t m_attribute;
	ThreadAttr m_threadAttribute;
};

/**
 *  \file   Thread.h   
 *  \class  ThreadPool
 *  \brief  线程池
 */
class ThreadPool:public Singleton<ThreadPool>{
	DECL_SINGLETON(ThreadPool)
	{
	}
public:
    ~ThreadPool(){};
    bool init(int maxThreadCount);
    int start(const Runnable& runnable,int policy, int priority);
    bool cancel(int threadID);
    int maxThreadCount();
    int idleThreadCount();
private:
    Mutex m_vectMutex;
    std::vector<std::unique_ptr<Thread>> m_threadVect;
    int m_maxThreadCount{0};
    int m_usedThreadCount{0};
};

}
#endif
